home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_10_01 / cmenu.exe / CMENU2.C < prev    next >
Text File  |  1991-12-11  |  14KB  |  600 lines

  1. /************************************************************
  2.  *    Program: CMENU Menu Compiler
  3.  *  Module: cmenu2.c    
  4.  *        Menu Compiler:
  5.  *        Menu/Item Token Processing Functions
  6.  *    Written by: Leor Zolman, 7/91
  7.  ************************************************************/
  8.  
  9. #include "cmenu.h"
  10. #include "ccmenu.h"
  11.  
  12. #include <ctype.h>
  13.  
  14.  
  15. /************************************************************
  16.  * do_menu():
  17.  *    Process the MENU keyword
  18.  ************************************************************/
  19.  
  20. int do_menu()
  21. {
  22.     int tok;
  23.  
  24.     if (in_menu)        /* Are we currently processing a menu?    */
  25.     {                    /* yes.                                    */
  26.         warning("Endmenu missing from previous menu");
  27.         do_endmenu();    /* give them the benefit of the doubt    */
  28.     }
  29.  
  30.     if ((tok = gettok()) != T_STRING)
  31.     {
  32.         if (n_menus)
  33.             error("Menu name missing; menu unreachable");
  34.         sprintf(tparam, "menu%d", n_menus + 1);    /* force a name        */
  35.         ungettok(tok);
  36.     }
  37.     
  38.     if (strlen(tparam) > MAX_NAME)
  39.     {
  40.         error("The name '%s' is too long (%d chars max)",
  41.                 tparam, MAX_NAME);
  42.         tparam[MAX_NAME] = '\0';                /* truncate name    */
  43.     }
  44.     
  45.     if ((MIp = find_menu(tparam)) == NULL)        /* menu exist?        */
  46.     {
  47.         MInfo[n_menus] = create_menu(tparam);    /* no.                */
  48.         if (fatal)
  49.             return ERROR;                        /* creation error    */
  50.         else
  51.             MIp = &MInfo[n_menus++];            /* OK, bump count    */
  52.     }
  53.     else
  54.         if (MIp -> Processed)                    /* redefinition?    */
  55.             return fatalerr("Duplicate Menu definition"); /* yes.    */
  56.         
  57.     Mp = &MIp -> Menu;
  58.     *Mp->title = *Mp->path = '\0';
  59.     Mp->nitems = Mp->widest = 0;
  60.     Mp->spacing = Mp->columns = Mp->escape = DEFAULT;
  61.     Mp->align = DEFAULT;
  62.  
  63.     in_item = FALSE;            /* state variables describing the    */    
  64.     in_menu = TRUE;                /* current menu being processed        */
  65.     n_items = 0;                
  66.     n_refs = 0;                    /* no forward item references yet    */
  67.  
  68.     if ((tok = gettok()) != T_COLON)            /* optional colon    */
  69.         ungettok(tok);
  70.     
  71.     return OK;
  72. }
  73.  
  74.  
  75. /************************************************************
  76.  * do_title():
  77.  *    Process the TITLE clause for a menu.
  78.  ************************************************************/
  79.  
  80. int do_title()
  81. {
  82.     int tok;
  83.  
  84.     if ((tok = gettok()) != T_STRING)
  85.     {
  86.         error("Title text missing");
  87.         ungettok(tok);
  88.     }
  89.         
  90.     if (!in_item)            /* Before all items?        */
  91.     {                        /* yes.                        */
  92.         if (*Mp->title)
  93.             return error("A Menu Title has already been specified");
  94.         strcpy(Mp->title, tparam);
  95.     }
  96.     else
  97.         return error("The Menu Title must precede all Menu Items.");
  98.  
  99.     return OK;
  100. }
  101.  
  102.  
  103. /************************************************************
  104.  * do_path():
  105.  *    Process the PATH option.
  106.  *    Note that the PATH option may apply to an entire
  107.  *    menu or just to a single menu item (determined
  108.  *    by context.)
  109.  ************************************************************/
  110.  
  111. int do_path()
  112. {
  113.     int tok;
  114.     char *cp;
  115.     
  116.     if ((tok = gettok()) != T_STRING)
  117.     {
  118.         error("Path text missing");
  119.         ungettok(tok);
  120.     }
  121.         
  122.     if (tparam[strlen(tparam)-1] == '/' || tparam[strlen(tparam)-1] == '\\')
  123.         tparam[strlen(tparam) - 1] = '\0';    /* delete traling slash  */
  124.  
  125.     if (!in_item)            /* Referring to the menu?    */
  126.     {                        /* yes.                        */
  127.         if (*Mp->path)
  128.             return error("A Menu Path has already been specified");
  129.         strcpy(Mp->path, tparam);
  130.     }
  131.     else
  132.     {                        /* Must be for the item.    */
  133.         if (*Ip->path)
  134.             return error("An Item Path has already been specified");
  135.         strcpy(Ip->path, tparam);
  136.     }
  137.     return OK;
  138. }
  139.  
  140.  
  141. /************************************************************
  142.  * do_align():
  143.  *    Process text alignment option.
  144.  *  Note: this option is a no-op. I decided there wasn't
  145.  *    any real need for any other than left-justified item
  146.  *    alignment. But, in case anyone thinks of a use for it,
  147.  *    I'm leaving in the ability to process the option.
  148.  ************************************************************/
  149.  
  150. int do_align()
  151. {
  152.     int tok;
  153.     
  154.     if (in_item)
  155.         return error("The Align clause must precede all Menu Items.");
  156.  
  157.     if (Mp->align)
  158.         return error("Align option already specified for this menu");
  159.     
  160.     switch (tok = gettok())
  161.     {
  162.         case T_LEFT:
  163.             Mp->align = 'L'; 
  164.             break;
  165.             
  166.         case T_RIGHT:
  167.             Mp->align = 'R';
  168.             break;
  169.             
  170.         case T_CENTER:
  171.             Mp->align = 'C';
  172.             break;
  173.             
  174.         default:
  175.             ungettok(tok);
  176.             return error("Align missing valid modifier");
  177.     }
  178.     return OK;
  179. }
  180.  
  181.  
  182. /************************************************************
  183.  * do_spacing():
  184.  *    Process the SPACING option (applies
  185.  *    to menus only.)
  186.  ************************************************************/
  187.  
  188. int do_spacing()
  189. {
  190.     int tok;
  191.  
  192.     if ((tok = gettok()) != T_VALUE)
  193.     {
  194.         error("Spacing value missing");
  195.         ungettok(tok);
  196.     }
  197.  
  198.     if (in_item)
  199.         return error("Spacing option must precede all menu items");
  200.  
  201.     if (Mp->spacing)
  202.         return error("Spacing option already specified");
  203.  
  204.              /* only single and double spacing supported    */
  205.     if (vparam != 1 && vparam != 2)
  206.         return error("Spacing value must be either 1 or 2");
  207.  
  208.     Mp->spacing = vparam;
  209.     return OK;
  210. }
  211.  
  212.  
  213. /************************************************************
  214.  * do_columns():
  215.  *    Process the COLUMNS option
  216.  ************************************************************/
  217.  
  218. int do_columns()
  219. {
  220.     int tok;
  221.     
  222.     if ((tok = gettok()) != T_VALUE)
  223.     {
  224.         error("Columns value missing");
  225.         ungettok(tok);
  226.     }
  227.  
  228.     if (in_item)
  229.         return error("Columns option must precede all menu items");
  230.  
  231.     if (Mp->columns)
  232.         return error("Columns option already specified");
  233.  
  234.     if (vparam < 1 || vparam > 6)    /*  6 seems a reasonable max. */
  235.         return error("Columns value must be between 1 and 6");
  236.     Mp->columns = vparam;
  237.     return OK;
  238. }
  239.  
  240.  
  241. /************************************************************
  242.  * do_escape():
  243.  *    Process "escape" and "noescape" menu options
  244.  ************************************************************/
  245.  
  246. int do_escape()
  247. {
  248.     if (in_item)
  249.         return error("\"%s\" must appear before all menu items",
  250.             keywords[token].keyword);
  251.     
  252.     if (Mp->escape)
  253.         return error("Escape option already specified");
  254.     Mp->escape = (token == T_ESCAPE) ? YES : NO;
  255.  
  256.     return OK;
  257. }
  258.  
  259.  
  260. /************************************************************
  261.  * do_endmenu():
  262.  *    Process ENDMENU keyword
  263.  ************************************************************/
  264.  
  265. int do_endmenu()
  266. {
  267.     int i;
  268.     
  269.     if (!n_items)
  270.         error("No menu items specified for this menu");
  271.     
  272.     for (i = 0; i < n_refs; i++)        /* check for unresolved        */
  273.     {                                    /* forward Item references    */
  274.         if (*fwd_refs[i].refp == UNDEF_FWD)
  275.         {
  276.             int save_lineno = lineno;
  277.             lineno = fwd_refs[i].lineno;
  278.             error("Unresolved reference to Item \"%s\"",
  279.                 fwd_refs[i].iname);
  280.             lineno = save_lineno;
  281.         }
  282.     }
  283.     
  284.     in_menu = in_item = FALSE;            /* done with current menu    */
  285.     MIp -> Processed = TRUE;            /* it is now processed        */
  286.     Mp -> nitems = n_items;
  287.     return OK;
  288. }
  289.  
  290.  
  291. /************************************************************
  292.  * do_item():
  293.  *    Process the ITEM clause. Create a new ite
  294.  *    and fill in any existing forward references to it.
  295.  ************************************************************/
  296.  
  297. int do_item()
  298. {
  299.     int tok, i;
  300.     char *cp, c;
  301.     
  302.     if (n_items)
  303.         itemcheck();    /* check for previous item's completion */
  304.  
  305.     if ((tok = gettok()) != T_STRING)    /* label specified?        */
  306.     {                                    /* If not, stuff unique    */
  307.         sprintf(tparam,"dummy!%d", n_items);  /* dummy name in    */    
  308.             ungettok(tok);
  309.     }
  310.     else
  311.     {
  312.         if (strlen(tparam) > MAX_NAME)
  313.         {
  314.             error("Item name \"%s\" too long. Max %d chars.",
  315.                         tparam, MAX_NAME);
  316.             tparam[MAX_NAME] = '\0';
  317.         }
  318.         else for (cp = tparam; c = *cp; cp++)
  319.             if (!(isalpha(c) || isdigit(c) || c == '_'))
  320.             {
  321.                 error("Invalid char in identifier name: \"%s\"",
  322.                             tparam);
  323.                 *cp = '\0';
  324.                 break;
  325.             }
  326.     }
  327.     
  328.     if ((IIp = find_item(tparam)) != NULL)    /* Item name found?    */
  329.         return error("Item name previously used.");
  330.  
  331.     if ((MIp->Items[n_items] = IIp = create_item(tparam))
  332.                 == NULL)
  333.         return ERROR;
  334.  
  335.     in_item = TRUE;
  336.     Ip = &IIp->Item;
  337.  
  338.     for (i = 0; i < n_refs; i++)        /* check for fwd refs    */
  339.         if (!strcmp(fwd_refs[i].iname, tparam))
  340.             *fwd_refs[i].refp